package workflow

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"math"
	"os"
	"path/filepath"
	"regexp"
	"sort"
	"strings"
	"sync"
	"time"

	"ai-rag/config"

	"net/http"

	"github.com/cloudwego/eino/components/document"
	"github.com/cloudwego/eino/components/embedding"
	"github.com/cloudwego/eino/components/indexer"
	"github.com/cloudwego/eino/components/model"
	"github.com/cloudwego/eino/components/prompt"
	"github.com/cloudwego/eino/components/retriever"
	"github.com/cloudwego/eino/compose"
	"github.com/cloudwego/eino/flow/retriever/router"
	"github.com/cloudwego/eino/schema"
	"github.com/sirupsen/logrus"
)

// RAGSystem 是一个完整的RAG系统实现
type RAGSystem struct {
	config        *config.Config
	indexWorkflow compose.Runnable[document.Source, []string]
	queryWorkflow compose.Runnable[string, *schema.Message]
	indexer       indexer.Indexer
	retriever     retriever.Retriever
}

// NewRAGSystem 创建新的RAG系统实例
func NewRAGSystem(config *config.Config) (*RAGSystem, error) {
	logrus.Info("初始化RAG系统")
	ctx := context.Background()

	// 1. 初始化各个组件
	loader := &DocumentLoader{config: config.Document.Loader}
	transformer := &SmartDocumentSplitter{
		ChunkSize:         config.Document.Transformer.MaxChunkSize,
		ChunkOverlap:      config.Document.Transformer.ChunkOverlap,
		PreserveSentences: true,
	}
	embedder := NewEmbedder(config.Embedding)
	idx := NewIndexer(config.Indexer)
	vectorRetriever := &VectorRetriever{config: config.Retriever, indexer: idx, embedder: embedder}
	keywordRetriever := &KeywordRetriever{config: config.Retriever, indexer: idx}
	chatModel := &ChatModel{config: config.Model}

	// 记录配置信息（不记录敏感信息）
	logrus.WithFields(logrus.Fields{
		"indexer_type":   config.Indexer.Type,
		"embedding_type": config.Embedding.Type,
		"retriever_type": config.Retriever.RetrieverType,
	}).Info("RAG系统配置已加载")

	// 2. 构建高级检索器（多查询+路由器）
	advancedRetriever, err := createAdvancedRetriever(ctx, vectorRetriever, keywordRetriever, chatModel)
	if err != nil {
		return nil, fmt.Errorf("创建高级检索器失败: %w", err)
	}

	// 3. 构建索引工作流
	indexWorkflow, err := buildIndexWorkflow(ctx, loader, transformer, embedder, idx)
	if err != nil {
		return nil, fmt.Errorf("构建索引工作流失败: %w", err)
	}

	// 4. 构建查询工作流
	queryWorkflow, err := buildQueryWorkflow(ctx, advancedRetriever, chatModel, config.Model.SystemPrompt)
	if err != nil {
		return nil, fmt.Errorf("构建查询工作流失败: %w", err)
	}

	logrus.Info("RAG系统初始化完成")
	return &RAGSystem{
		config:        config,
		indexWorkflow: indexWorkflow,
		queryWorkflow: queryWorkflow,
		indexer:       idx,
		retriever:     advancedRetriever,
	}, nil
}

// buildIndexWorkflow 构建索引工作流
func buildIndexWorkflow(
	ctx context.Context,
	loader document.Loader,
	transformer document.Transformer,
	embedder embedding.Embedder,
	indexer indexer.Indexer,
) (compose.Runnable[document.Source, []string], error) {
	// 创建工作流
	wf := compose.NewWorkflow[document.Source, []string]()

	// 1. 添加文档加载节点
	loaderNode := wf.AddLoaderNode("loader", loader)
	loaderNode.AddInput(compose.START)

	// 2. 添加文档转换节点（分割等）
	transformerNode := wf.AddDocumentTransformerNode("transformer", transformer)
	transformerNode.AddInput("loader")

	// 3. 添加向量嵌入节点
	embedderNode := wf.AddEmbeddingNode("embedder", embedder)
	embedderNode.AddInput("transformer", compose.MapFields("Content", ""))

	// 4. 添加向量分配Lambda节点
	assignVectorNode := wf.AddLambdaNode("assign_vector", compose.InvokableLambda(
		func(ctx context.Context, data struct {
			Docs    []*schema.Document `map:"transformer"`
			Vectors [][]float64        `map:"embedder"`
		}) ([]*schema.Document, error) {
			// 将向量分配给对应文档
			if len(data.Docs) != len(data.Vectors) {
				return nil, fmt.Errorf("documents and vectors length mismatch")
			}

			for i := range data.Docs {
				// 将向量存储在文档的元数据中
				data.Docs[i].MetaData["vector"] = data.Vectors[i]
			}
			return data.Docs, nil
		},
	))
	assignVectorNode.AddInput("transformer", compose.MapFields("", "Docs"))
	assignVectorNode.AddInput("embedder", compose.MapFields("", "Vectors"))

	// 5. 添加索引存储节点
	indexerNode := wf.AddIndexerNode("indexer", indexer)
	indexerNode.AddInput("assign_vector")

	// 6. 设置结束节点
	wf.End().AddInput("indexer")

	// 编译工作流
	return wf.Compile(ctx)
}

// buildQueryWorkflow 构建查询工作流
func buildQueryWorkflow(
	ctx context.Context,
	retriever retriever.Retriever,
	chatModel model.BaseChatModel,
	systemPrompt string,
) (compose.Runnable[string, *schema.Message], error) {
	// 创建工作流
	wf := compose.NewWorkflow[string, *schema.Message]()

	// 1. 添加检索节点
	retrieverNode := wf.AddRetrieverNode("retriever", retriever)
	retrieverNode.AddInput(compose.START)

	// 2. 添加提示构建节点
	template := createRAGPrompt(systemPrompt)
	templateNode := wf.AddChatTemplateNode("template", template)
	templateNode.AddInput(compose.START, compose.MapFields("", "query"))   // 用户查询
	templateNode.AddInput("retriever", compose.MapFields("", "documents")) // 检索到的文档

	// 3. 添加LLM生成节点
	modelNode := wf.AddChatModelNode("model", chatModel)
	modelNode.AddInput("template")

	// 4. 设置结束节点
	wf.End().AddInput("model")

	// 编译工作流
	return wf.Compile(ctx)
}

// createRAGPrompt 创建RAG提示模板
func createRAGPrompt(systemPrompt string) prompt.ChatTemplate {
	if systemPrompt == "" {
		systemPrompt = "你是一个有用的助手，基于提供的文档回答用户问题。请仅使用文档中的信息回答问题。如果文档中没有相关信息，请说明你不知道。"
	}

	// 使用Jinja2模板语法
	return prompt.FromMessages(schema.Jinja2,
		schema.SystemMessage(systemPrompt),
		schema.UserMessage(`
文档:
{% for doc in documents %}
{{ doc.content }}
{% endfor %}

问题: {{ query }}
`),
	)
}

// createAdvancedRetriever 创建高级检索器（结合多查询和路由器）
func createAdvancedRetriever(
	ctx context.Context,
	vectorRetriever retriever.Retriever,
	keywordRetriever retriever.Retriever,
	chatModel interface{}, // 使用interface{}以避免接口不匹配问题
) (retriever.Retriever, error) {
	// 首先创建路由器检索器
	routerRetriever, err := router.NewRetriever(ctx, &router.Config{
		Retrievers: map[string]retriever.Retriever{
			"vector":  vectorRetriever,
			"keyword": keywordRetriever,
		},
		FusionFunc: rrfFusion,
	})
	if err != nil {
		return nil, err
	}

	// 注意：在实际实现中，可能需要根据具体的接口要求调整这里的实现
	// 暂时只返回路由器检索器作为简化版本
	return routerRetriever, nil
}

// rrfFusion 实现RRF融合算法
func rrfFusion(ctx context.Context, result map[string][]*schema.Document) ([]*schema.Document, error) {
	docRankMap := make(map[string]float64)
	docMap := make(map[string]*schema.Document)

	for _, docs := range result {
		for i, doc := range docs {
			docMap[doc.ID] = doc
			docRankMap[doc.ID] += 1.0 / float64(i+60) // RRF公式
		}
	}

	docList := make([]*schema.Document, 0, len(docMap))
	for id := range docMap {
		docList = append(docList, docMap[id])
	}

	sort.Slice(docList, func(i, j int) bool {
		return docRankMap[docList[i].ID] > docRankMap[docList[j].ID]
	})

	return docList, nil
}

// IndexDocument 索引单个文档
func (s *RAGSystem) IndexDocument(ctx context.Context, filePath string) ([]string, error) {
	source := document.Source{URI: filePath}
	return s.indexWorkflow.Invoke(ctx, source)
}

// BatchIndexDocuments 批量索引文档
func (s *RAGSystem) BatchIndexDocuments(ctx context.Context, filePaths []string, batchSize int) error {
	for i := 0; i < len(filePaths); i += batchSize {
		end := i + batchSize
		if end > len(filePaths) {
			end = len(filePaths)
		}

		// 并行处理批次中的文档
		var wg sync.WaitGroup
		for _, filePath := range filePaths[i:end] {
			wg.Add(1)
			go func(path string) {
				defer wg.Done()
				_, err := s.IndexDocument(ctx, path)
				if err != nil {
					logrus.WithError(err).WithField("path", path).Error("索引文档失败")
				}
			}(filePath)
		}
		wg.Wait()
	}
	return nil
}

// AnswerQuery 回答查询
func (s *RAGSystem) AnswerQuery(ctx context.Context, query string) (string, error) {
	response, err := s.queryWorkflow.Invoke(ctx, query)
	if err != nil {
		return "", err
	}
	return response.Content, nil
}

// Close 关闭RAG系统
func (s *RAGSystem) Close() error {
	logrus.Info("关闭RAG系统")
	// 如果索引器实现了自定义的Close方法，可以调用
	if idx, ok := s.indexer.(interface{ Close() error }); ok {
		return idx.Close()
	}
	return nil
}

// DocumentLoader 自定义文档加载器
type DocumentLoader struct {
	config config.LoaderConfig
}

// Load 实现document.Loader接口
func (l *DocumentLoader) Load(ctx context.Context, src document.Source, opts ...document.LoaderOption) ([]*schema.Document, error) {
	path := src.URI
	logrus.WithField("path", path).Info("加载文档")

	// 根据文件扩展名选择加载方法
	ext := strings.ToLower(filepath.Ext(path))

	// 检查文件是否存在
	if _, err := os.Stat(path); os.IsNotExist(err) {
		return nil, fmt.Errorf("文件不存在: %w", err)
	}

	// 获取文件内容
	content, err := os.ReadFile(path)
	if err != nil {
		return nil, fmt.Errorf("读取文件失败: %w", err)
	}

	// 提取文件信息作为元数据
	fileInfo, err := os.Stat(path)
	if err != nil {
		logrus.WithError(err).WithField("path", path).Warn("获取文件信息失败")
	}

	metadata := make(map[string]interface{})
	metadata["source"] = path
	metadata["file_name"] = filepath.Base(path)
	metadata["file_size"] = len(content)
	metadata["file_type"] = ext[1:] // 去掉点号
	if fileInfo != nil {
		metadata["modified_time"] = fileInfo.ModTime()
	}

	// 特殊处理HTML文件
	docContent := string(content)
	if ext == ".html" || ext == ".htm" {
		// 移除HTML标签以获取纯文本
		docContent = regexp.MustCompile(`(?s)<script[^>]*>.*?</script>`).ReplaceAllString(docContent, "")
		docContent = regexp.MustCompile(`(?s)<style[^>]*>.*?</style>`).ReplaceAllString(docContent, "")
		docContent = regexp.MustCompile(`<[^>]+>`).ReplaceAllString(docContent, " ")
		docContent = regexp.MustCompile(`\s+`).ReplaceAllString(docContent, " ")
		docContent = strings.TrimSpace(docContent)
	}

	return []*schema.Document{
		{
			Content:  docContent,
			MetaData: metadata,
		},
	}, nil
}

// SmartDocumentSplitter 智能文档分割器
type SmartDocumentSplitter struct {
	ChunkSize         int
	ChunkOverlap      int
	PreserveSentences bool
}

// Transform 实现document.Transformer接口
func (s *SmartDocumentSplitter) Transform(ctx context.Context, docs []*schema.Document, opts ...document.TransformerOption) ([]*schema.Document, error) {
	var result []*schema.Document

	for _, doc := range docs {
		chunks := s.splitDocument(doc.Content)

		// 为每个块创建一个新文档，并保留原始元数据
		for i, chunk := range chunks {
			chunkDoc := &schema.Document{
				ID:       fmt.Sprintf("%s_chunk_%d", doc.ID, i),
				Content:  chunk,
				MetaData: make(map[string]interface{}),
			}

			// 复制原始元数据
			for k, v := range doc.MetaData {
				chunkDoc.MetaData[k] = v
			}

			// 添加分块信息
			chunkDoc.MetaData["chunk_index"] = i
			chunkDoc.MetaData["chunk_total"] = len(chunks)

			// 提取标题和章节信息
			if title := extractTitle(chunk); title != "" {
				chunkDoc.MetaData["title"] = title
			}

			result = append(result, chunkDoc)
		}
	}

	return result, nil
}

// splitDocument 根据配置分割文档
func (s *SmartDocumentSplitter) splitDocument(content string) []string {
	if s.PreserveSentences {
		return s.splitBySentences(content)
	}
	return s.splitBySize(content)
}

// splitBySentences 按句子分割文档
func (s *SmartDocumentSplitter) splitBySentences(content string) []string {
	// 简单的句子分割正则（句号、问号、感叹号后跟空格或换行）
	sentenceRegex := regexp.MustCompile(`[.!?](?:\s|\n|$)`)
	sentences := sentenceRegex.Split(content, -1)

	var chunks []string
	var currentChunk strings.Builder
	var currentSize int

	for i, sentence := range sentences {
		if sentence == "" {
			continue
		}

		// 重新添加标点符号
		if i < len(sentences)-1 {
			sentence += content[len(sentence):][0:1] // 添加标点
		}

		sentenceSize := len(sentence)

		// 如果添加这个句子会超出块大小，且当前块不为空，则创建新块
		if currentSize > 0 && currentSize+sentenceSize > s.ChunkSize {
			chunks = append(chunks, strings.TrimSpace(currentChunk.String()))
			currentChunk.Reset()
			currentSize = 0

			// 添加重叠内容
			if s.ChunkOverlap > 0 && len(chunks) > 0 {
				lastChunk := chunks[len(chunks)-1]
				overlapStart := len(lastChunk) - s.ChunkOverlap
				if overlapStart < 0 {
					overlapStart = 0
				}
				currentChunk.WriteString(lastChunk[overlapStart:])
				currentSize += len(lastChunk[overlapStart:])
			}
		}

		currentChunk.WriteString(sentence)
		currentSize += sentenceSize
	}

	// 添加最后一个块
	if currentSize > 0 {
		chunks = append(chunks, strings.TrimSpace(currentChunk.String()))
	}

	return chunks
}

// splitBySize 按大小分割文档
func (s *SmartDocumentSplitter) splitBySize(content string) []string {
	content = strings.TrimSpace(content)
	contentLen := len(content)

	if contentLen <= s.ChunkSize {
		return []string{content}
	}

	var chunks []string
	for i := 0; i < contentLen; i += s.ChunkSize - s.ChunkOverlap {
		end := i + s.ChunkSize
		if end > contentLen {
			end = contentLen
		}
		chunks = append(chunks, content[i:end])
	}

	return chunks
}

// extractTitle 从文本中提取标题
func extractTitle(text string) string {
	// 查找以#开头的行（Markdown标题）
	lines := strings.Split(text, "\n")
	for _, line := range lines {
		trimmed := strings.TrimSpace(line)
		if strings.HasPrefix(trimmed, "#") {
			return strings.TrimSpace(strings.TrimLeft(trimmed, "# "))
		}
	}

	// 查找首行作为标题
	if len(lines) > 0 {
		firstLine := strings.TrimSpace(lines[0])
		if len(firstLine) > 0 && len(firstLine) < 100 {
			return firstLine
		}
	}

	return ""
}

// Embedder 向量嵌入器
type Embedder struct {
	config config.EmbeddingConfig
	client *http.Client
}

// NewEmbedder 创建新的嵌入器
func NewEmbedder(config config.EmbeddingConfig) *Embedder {
	return &Embedder{
		config: config,
		client: &http.Client{
			Timeout: 30 * time.Second,
		},
	}
}

// Embed 实现embedding.Embedder接口
func (e *Embedder) Embed(ctx context.Context, docs []*schema.Document, opts ...embedding.Option) ([][]float64, error) {
	// 提取文档内容
	contents := make([]string, len(docs))
	for i, doc := range docs {
		contents[i] = doc.Content
	}

	return e.EmbedStrings(ctx, contents, opts...)
}

// EmbedStrings 实现embedding.Embedder接口的EmbedStrings方法
func (e *Embedder) EmbedStrings(ctx context.Context, texts []string, opts ...embedding.Option) ([][]float64, error) {
	logrus.WithField("count", len(texts)).Info("生成嵌入向量")

	// 如果配置了服务器URL，调用外部服务
	if e.config.ServerURL != "" {
		return e.callEmbeddingAPI(ctx, texts)
	}

	// 否则使用模拟实现
	results := make([][]float64, len(texts))
	for i := range texts {
		vectorSize := e.config.EmbeddingDim
		if vectorSize <= 0 {
			vectorSize = 768 // 默认尺寸
		}

		vector := make([]float64, vectorSize)
		// 填充一些模拟数据
		for j := range vector {
			vector[j] = float64(i+j) * 0.01
		}

		results[i] = vector
	}

	return results, nil
}

// callEmbeddingAPI 调用嵌入API服务
func (e *Embedder) callEmbeddingAPI(ctx context.Context, texts []string) ([][]float64, error) {
	// 构建请求体
	reqBody := struct {
		Model string   `json:"model"`
		Texts []string `json:"texts"`
	}{}

	if e.config.ModelName != "" {
		reqBody.Model = e.config.ModelName
	} else {
		reqBody.Model = "doubao-embedding-text-240715" // 默认模型
	}

	reqBody.Texts = texts

	// 转换为JSON
	data, err := json.Marshal(reqBody)
	if err != nil {
		return nil, fmt.Errorf("序列化请求失败: %w", err)
	}

	// 创建请求
	req, err := http.NewRequestWithContext(ctx, "POST", e.config.ServerURL, bytes.NewBuffer(data))
	if err != nil {
		return nil, fmt.Errorf("创建请求失败: %w", err)
	}

	req.Header.Set("Content-Type", "application/json")

	// 发送请求
	resp, err := e.client.Do(req)
	if err != nil {
		logrus.WithError(err).WithField("url", e.config.ServerURL).Error("调用嵌入API失败")
		// 如果API调用失败，返回模拟数据以保证系统继续运行
		return e.getMockEmbeddings(len(texts)), nil
	}
	defer resp.Body.Close()

	// 检查响应状态
	if resp.StatusCode != http.StatusOK {
		body, _ := io.ReadAll(resp.Body)
		logrus.WithField("status", resp.Status).WithField("body", string(body)).Error("嵌入API返回错误状态")
		// 如果API返回错误，返回模拟数据以保证系统继续运行
		return e.getMockEmbeddings(len(texts)), nil
	}

	// 解析响应
	var response struct {
		Embeddings [][]float64 `json:"embeddings"`
	}

	if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
		return nil, fmt.Errorf("解析响应失败: %w", err)
	}

	return response.Embeddings, nil
}

// getMockEmbeddings 生成模拟嵌入向量
func (e *Embedder) getMockEmbeddings(count int) [][]float64 {
	vectorSize := e.config.EmbeddingDim
	if vectorSize <= 0 {
		vectorSize = 768
	}

	results := make([][]float64, count)
	for i := range results {
		vector := make([]float64, vectorSize)
		for j := range vector {
			vector[j] = float64(i+j) * 0.01
		}
		results[i] = vector
	}
	return results
}

// Indexer 向量索引器
type Indexer struct {
	config       config.IndexerConfig
	index        map[string]*schema.Document // 简单的内存索引实现（作为回退）
	milvusClient interface{}                 // Milvus客户端接口
	mutex        sync.RWMutex
}

// NewIndexer 创建新的索引器
func NewIndexer(config config.IndexerConfig) *Indexer {
	idx := &Indexer{
		config: config,
		index:  make(map[string]*schema.Document),
	}

	// 如果配置了Milvus，尝试初始化
	if config.Type == "milvus" {
		idx.initMilvusClient()
	}

	return idx
}

// initMilvusClient 初始化Milvus客户端
func (i *Indexer) initMilvusClient() {
	logrus.Info("初始化Milvus客户端")
	// 这里应该是Milvus客户端的实际初始化代码
	// 由于没有完整的Milvus SDK导入，这里暂时设置为nil
	// 实际使用时需要替换为真实的Milvus客户端初始化

	// 示例代码（需要导入相应的Milvus SDK）：
	// client, err := milvus.NewClient(context.Background(),
	//     milvus.Config{
	//         Host:     i.config.MilvusHost,
	//         Port:     i.config.MilvusPort,
	//         Username: i.config.MilvusUser,
	//         Password: i.config.MilvusPassword,
	//     })
	// if err != nil {
	//     logrus.WithError(err).Error("初始化Milvus客户端失败，将使用内存索引作为回退")
	//     return
	// }
	// i.milvusClient = client

	logrus.Info("Milvus客户端初始化完成")
}

// Store 实现indexer.Indexer接口
func (i *Indexer) Store(ctx context.Context, docs []*schema.Document, opts ...indexer.Option) ([]string, error) {
	logrus.WithField("count", len(docs)).Info("存储文档到索引")

	// 尝试使用Milvus存储
	if i.milvusClient != nil {
		logrus.Info("使用Milvus存储文档")
		// 这里应该是实际的Milvus存储代码
		// 由于没有完整的Milvus SDK，这里暂时返回模拟ID

		ids := make([]string, len(docs))
		for i, doc := range docs {
			if doc.ID == "" {
				doc.ID = fmt.Sprintf("milvus_doc_%d", time.Now().UnixNano()+int64(i))
			}
			ids[i] = doc.ID
		}

		return ids, nil
	}

	// 回退到内存存储
	i.mutex.Lock()
	defer i.mutex.Unlock()

	ids := make([]string, 0, len(docs))
	for _, doc := range docs {
		// 如果文档没有ID，生成一个
		if doc.ID == "" {
			doc.ID = fmt.Sprintf("memory_doc_%d", time.Now().UnixNano())
		}

		i.index[doc.ID] = doc
		ids = append(ids, doc.ID)
	}

	return ids, nil
}

// Search 自定义搜索方法，因为Indexer接口可能没有Retrieve方法
func (i *Indexer) Search(ctx context.Context, query []float64, topK int) ([]*schema.Document, error) {
	// 尝试使用Milvus搜索
	if i.milvusClient != nil {
		logrus.Info("使用Milvus搜索文档")
		// 这里应该是实际的Milvus搜索代码
		// 由于没有完整的Milvus SDK，这里暂时返回空结果

		return []*schema.Document{}, nil
	}

	// 回退到内存搜索
	i.mutex.RLock()
	defer i.mutex.RUnlock()

	// 简单的相似性搜索实现
	type scoredDoc struct {
		doc   *schema.Document
		score float64
	}

	var scoredDocs []scoredDoc
	for _, doc := range i.index {
		// 假设文档结构中存储了向量
		// 这里使用文档的元数据来存储向量
		if vectorData, ok := doc.MetaData["vector"].([]float64); ok && len(vectorData) > 0 {
			score := cosineSimilarity(query, vectorData)
			scoredDocs = append(scoredDocs, scoredDoc{doc: doc, score: score})
		}
	}

	// 按得分排序
	sort.Slice(scoredDocs, func(a, b int) bool {
		return scoredDocs[a].score > scoredDocs[b].score
	})

	// 取前topK个结果
	result := make([]*schema.Document, 0, topK)
	for i := 0; i < len(scoredDocs) && i < topK; i++ {
		result = append(result, scoredDocs[i].doc)
	}

	return result, nil
}

// Close 自定义Close方法
func (i *Indexer) Close() error {
	logrus.Info("关闭索引器")

	// 关闭Milvus客户端
	if i.milvusClient != nil {
		logrus.Info("关闭Milvus客户端")
		// 这里应该是实际的Milvus客户端关闭代码
		// 由于没有完整的Milvus SDK，这里暂时跳过
	}

	return nil
}

// VectorRetriever 向量检索器
type VectorRetriever struct {
	config   config.RetrieverConfig
	indexer  *Indexer // 使用具体类型而不是接口
	embedder embedding.Embedder
}

// Retrieve 实现retriever.Retriever接口
func (v *VectorRetriever) Retrieve(ctx context.Context, query string, opts ...retriever.Option) ([]*schema.Document, error) {
	// 1. 将查询文本转换为向量
	vectors, err := v.embedder.EmbedStrings(ctx, []string{query})
	if err != nil {
		return nil, fmt.Errorf("嵌入查询失败: %w", err)
	}

	if len(vectors) == 0 {
		return nil, fmt.Errorf("嵌入结果为空")
	}

	// 2. 从索引器检索相似文档
	return v.indexer.Search(ctx, vectors[0], v.config.TopK)
}

// KeywordRetriever 关键词检索器
type KeywordRetriever struct {
	config  config.RetrieverConfig
	indexer indexer.Indexer
}

// Retrieve 实现retriever.Retriever接口
func (k *KeywordRetriever) Retrieve(ctx context.Context, query string, opts ...retriever.Option) ([]*schema.Document, error) {
	// 简单的关键词匹配实现
	// 实际实现应使用更复杂的文本匹配算法
	keywords := strings.Fields(strings.ToLower(query))

	// 这里假设indexer可以作为文档存储使用
	// 实际实现可能需要单独的文本索引
	if idx, ok := k.indexer.(*Indexer); ok {
		idx.mutex.RLock()
		defer idx.mutex.RUnlock()

		var results []*schema.Document
		for _, doc := range idx.index {
			docText := strings.ToLower(doc.Content)
			score := 0
			for _, keyword := range keywords {
				if strings.Contains(docText, keyword) {
					score++
				}
			}

			if score > 0 {
				results = append(results, doc)
			}
		}

		return results, nil
	}

	return []*schema.Document{}, nil
}

// ChatModel 聊天模型
type ChatModel struct {
	config config.ModelConfig
}

// Generate 实现model.BaseChatModel接口
func (c *ChatModel) Generate(ctx context.Context, messages []*schema.Message, opts ...model.Option) (*schema.Message, error) {
	logrus.Info("生成模型响应")

	// 实际实现应调用真实的LLM API
	// 这里提供一个简单的模拟实现
	response := "这是一个模拟的模型响应。在实际应用中，这里会调用真实的大语言模型。"

	return &schema.Message{
		Role:    "assistant",
		Content: response,
	}, nil
}

// Stream 实现model.BaseChatModel接口的Stream方法
func (c *ChatModel) Stream(ctx context.Context, messages []*schema.Message, opts ...model.Option) (*schema.StreamReader[*schema.Message], error) {
	// 简单的流式响应实现框架
	// 实际实现应返回一个能生成流式响应的StreamReader
	return nil, fmt.Errorf("流式响应尚未实现")
}

// cosineSimilarity 计算两个向量的余弦相似度
func cosineSimilarity(a, b []float64) float64 {
	if len(a) != len(b) {
		return 0
	}

	var dotProduct, normA, normB float64
	for i := range a {
		dotProduct += a[i] * b[i]
		normA += a[i] * a[i]
		normB += b[i] * b[i]
	}

	if normA == 0 || normB == 0 {
		return 0
	}

	return dotProduct / (sqrt(normA) * sqrt(normB))
}

// sqrt 使用math包的平方根函数
func sqrt(x float64) float64 {
	return math.Sqrt(x)
}
